package com.cougil.uoc.seghismed.business.impl;

import iaik.asn1.ObjectID;
import iaik.asn1.structures.Name;
import iaik.x509.X509Certificate;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;

import com.cougil.uoc.seghismed.business.CipherService;
import com.cougil.uoc.seghismed.cipher.CipherManager;
import com.cougil.uoc.seghismed.cipher.P12;
import com.cougil.uoc.seghismed.cipher.SignerCipherManager;
import com.cougil.uoc.seghismed.model.Alergia;
import com.cougil.uoc.seghismed.model.Historial;
import com.cougil.uoc.seghismed.model.Metge;
import com.cougil.uoc.seghismed.model.Pacient;
import com.cougil.uoc.seghismed.model.Usuari;
import com.cougil.uoc.seghismed.model.Visita;
import com.cougil.uoc.seghismed.model.ciphed.AlergiaCiphed;
import com.cougil.uoc.seghismed.model.ciphed.HistorialCiphed;
import com.cougil.uoc.seghismed.model.ciphed.MetgeCiphed;
import com.cougil.uoc.seghismed.model.ciphed.PacientCiphed;
import com.cougil.uoc.seghismed.model.ciphed.UsuariCiphed;
import com.cougil.uoc.seghismed.model.ciphed.VisitaCiphed;
import com.cougil.uoc.seghismed.model.comunicacions.Peticio;
import com.cougil.uoc.seghismed.model.comunicacions.Resposta;
import com.cougil.uoc.seghismed.model.comunicacions.ciphed.PeticioCiphed;
import com.cougil.uoc.seghismed.model.comunicacions.ciphed.RespostaCiphed;
import com.cougil.uoc.seghismed.model.comunicacions.enums.Operacio;
import com.cougil.uoc.seghismed.model.comunicacions.enums.Resultat;
import com.cougil.uoc.seghismed.model.enums.GrupSanguini;
import com.cougil.uoc.seghismed.model.enums.UnitatOrganitzativa;
import com.cougil.uoc.seghismed.utils.SeghismedEnum;
import com.cougil.uoc.seghismed.utils.SeghismedException;
import com.cougil.uoc.seghismed.utils.SeghismedUtils;

/**
 * Classe principal que implementa els principals mètodes emprats per a xifrar i desxifrar
 * informació a Seghismed
 *
 * @author Ignacio Cougil Jares
 */

public class CipherServiceImpl implements CipherService {

	protected static final Logger logger = Logger.getLogger(CipherServiceImpl.class);

	private static Map<Usuari, P12> p12s = new HashMap<Usuari, P12>();

	private static Map<Usuari, X509Certificate> x509s = new HashMap<Usuari, X509Certificate>();

	static {
		SeghismedUtils.initIAIK();
	}

	private Usuari gestor;

	/**
	 * @param key
	 * @return
	 * @see java.util.Map#containsKey(java.lang.Object)
	 */
	public boolean containsP12(Usuari usuari) {
		return CipherServiceImpl.p12s.containsKey(usuari);
	}

	private Alergia desxifrarAlergia(CipherManager cm, AlergiaCiphed ac) {
		Alergia a = null;
		if (ac != null) {
			a = new Alergia();
			a.setDescripcio( cm.desxifrar(ac.getDescripcioCiphed()) );
			a.setId( this.desxifrarInteger(cm, ac.getIdCiphed()) );
		}
		return a;
	}


	private Set<Alergia> desxifrarAlergies(CipherManager cm,
			Set<AlergiaCiphed> alergiesCiphed) {
		Set<Alergia> alergies = null;
		// el conjunt d'al·lergies xifrades pot estar buida
		if (alergiesCiphed != null) {
			alergies = new HashSet<Alergia>();
			for (Iterator<AlergiaCiphed> iterator = alergiesCiphed.iterator(); iterator.hasNext();) {
				AlergiaCiphed aCiphed = iterator.next();
				alergies.add(this.desxifrarAlergia(cm, aCiphed));
			}
		}
		return alergies;
	}

	private Date desxifrarDate(CipherManager cm, byte[] data) {
		return SeghismedUtils.parseDate(cm.desxifrar(data));
	}

	private Enum desxifrarEnum(CipherManager cm, byte[] enumerat, Enum[] values) {
		return SeghismedUtils.parseEnum( cm.desxifrar(enumerat), values );
	}

	private Integer desxifrarInteger(CipherManager cm, byte[] integer) {
		return SeghismedUtils.parseInteger( cm.desxifrar(integer) );
	}

	private Metge desxifrarMetge(CipherManager cm, MetgeCiphed mCiphed) {
		Metge m = (Metge) this.desxifrarUsuari(cm, mCiphed);
		if (m != null) {
			m.setNumeroColegiat(cm.desxifrar(mCiphed.getNumeroColegiatCiphed()));
			m.setEspecialitat(cm.desxifrar(mCiphed.getEspecialitatCiphed()));
			// per defecte no incloem la informació del seus pacients protegits
			// m.setLlistaPacientsProt(mCiphed.getLlistaPacientsProt());
		}
		return m;
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.CipherService#desxifrarMetge(com.cougil.uoc.seghismed.model.ciphed.MetgeCiphed, com.cougil.uoc.seghismed.model.Usuari)
	 */
	@Override
	public Metge desxifrarMetge(MetgeCiphed mCiphed, Usuari destinatari) {
		Metge m = null;
		if (mCiphed != null) {

			// desxifrem amb la clau privada de l'usuari destinatari
			P12 p12 = this.getP12(destinatari);

			CipherManager cm = new CipherManager(p12.getPrivateKey());

			m = this.desxifrarMetge(cm, mCiphed);
		}
		return m;
	}

	private Map<Metge, Date> desxifrarMetgesAmbAccesProtegit(CipherManager cm,
			Map<MetgeCiphed, Date> metgesCiphed) {
		Map<Metge, Date> metges = new HashMap<Metge, Date>();

		for (Iterator<MetgeCiphed> iterator = metgesCiphed.keySet().iterator(); iterator.hasNext();) {
			MetgeCiphed metgeCiphedGestor = iterator.next();

			// desxifrem el metge
			Metge m = this.desxifrarMetge(cm, metgeCiphedGestor);

			// agafem també la data
			Date d = metgesCiphed.get(metgeCiphedGestor);

			metges.put(m, d);
		}
		return metges;
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.CipherService#desxifrarMetgesAmbAccesProtegit(java.util.Map, com.cougil.uoc.seghismed.model.Usuari)
	 */
	@Override
	public Map<Metge, Date> desxifrarMetgesAmbAccesProtegit(Map<MetgeCiphed, Date> metgesAmbAccesProtegit,
			Usuari destinatari) {
		P12 p12 = this.getP12(destinatari);
		CipherManager cmDecrypt = new CipherManager(p12.getPrivateKey());
		return this.desxifrarMetgesAmbAccesProtegit(cmDecrypt, metgesAmbAccesProtegit);
	}

	private Pacient desxifrarPacient(CipherManager cm, PacientCiphed pCiphed) {
		Pacient p = (Pacient) this.desxifrarUsuari(cm, pCiphed);
		p.setAlergies( this.desxifrarAlergies(cm, pCiphed.getAlergiesCiphed()) );
		p.setGrupSanguini(  (GrupSanguini)
				this.desxifrarEnum(cm, pCiphed.getGrupSanguiniCiphed(), GrupSanguini.values()));
		// per defecte no incloem la informació de l'historial (per seguretat i per
		// evitar crides recursives)
		//p.setHistorial(historialCiphed);
		return p;
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.CipherService#desxifrarPacient(com.cougil.uoc.seghismed.model.ciphed.PacientCiphed, com.cougil.uoc.seghismed.model.Usuari)
	 */
	public Pacient desxifrarPacient(PacientCiphed pCiphed, Usuari destinatari) {
		Pacient p = null;
		if (pCiphed != null) {

			// desxifrem amb la clau privada de l'usuari destinatari
			P12 p12 = this.getP12(destinatari);

			CipherManager cm = new CipherManager(p12.getPrivateKey());

			p = this.desxifrarPacient(cm, pCiphed);
		}
		return p;
	}

	private List<Pacient> desxifrarPacientsProtegits(CipherManager cm,
			List<PacientCiphed> pacientsCiphed) {
		List<Pacient> pacients = null;
		if (pacientsCiphed != null) {
			pacients = new ArrayList<Pacient>();
			for (Iterator<PacientCiphed> iterator = pacientsCiphed.iterator(); iterator.hasNext();) {
				PacientCiphed pacientCiphed = iterator.next();

				// desxifrem el pacient
				Pacient p = this.desxifrarPacient(cm, pacientCiphed);

				pacients.add(p);
			}
		}
		return pacients;
	}


	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * com.cougil.uoc.seghismed.business.CipherService#desxifrarPacientsProtegits(java.util.List,
	 * com.cougil.uoc.seghismed.model.Usuari)
	 */
	public List<Pacient> desxifrarPacientsProtegits(List<PacientCiphed> pacientsCiphed,
			Usuari destinatari) {
		P12 p12 = this.getP12(destinatari);
		CipherManager cmDecrypt = new CipherManager(p12.getPrivateKey());
		return this.desxifrarPacientsProtegits(cmDecrypt, pacientsCiphed);
	}


	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.CipherService#desxifrar(com.cougil.uoc.seghismed.model.comunicacions.ciphed.PeticioCiphed, com.cougil.uoc.seghismed.model.Usuari)
	 */
	@Override
	public Peticio desxifrarPeticio(PeticioCiphed pCiphed, Usuari destinatari) {
		CipherServiceImpl.logger.debug("Intentant desxifrar la peticio: ["+pCiphed+"]");
		Peticio p = new Peticio();

		// desxifrem amb la clau privada de l'usuari destinatari
		P12 p12 = this.getP12(destinatari);

		CipherManager cm = new CipherManager(p12.getPrivateKey());

		p.setNg( this.desxifrarInteger(cm, pCiphed.getNgCiphed()) );
		p.setNi( this.desxifrarInteger(cm, pCiphed.getNiCiphed()) );
		p.setOperacio( (Operacio) this.desxifrarEnum(cm, pCiphed.getNomOperacioCiphed(), Operacio
				.values()));
		p.setUsuariDesti(this.getUsuari(cm, pCiphed.getUsuariDestiCiphed()));
		p.setUsuariOrigen(this.getUsuari(cm, pCiphed.getUsuariOrigenCiphed()));


		CipherServiceImpl.logger.debug("Peticio desxifrada: ["+p+"]");
		return p;
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.CipherService#desxifrar(com.cougil.uoc.seghismed.model.comunicacions.ciphed.RespostaCiphed, com.cougil.uoc.seghismed.model.Usuari)
	 */
	@Override
	public Resposta desxifrarResposta(RespostaCiphed rCiphed, Usuari destinatari) {
		CipherServiceImpl.logger.debug("Intentant desxifrar la resposta: ["+rCiphed+"]");
		Resposta r = null;

		if (rCiphed != null) {
			r = new Resposta();

			// desxifrem amb la clau privada de l'usuari destinatari
			P12 p12 = this.getP12(destinatari);

			CipherManager cm = new CipherManager(p12.getPrivateKey());

			r.setNg(this.desxifrarInteger(cm, rCiphed.getNgCiphed()));
			r.setNi(this.desxifrarInteger(cm, rCiphed.getNiCiphed()));
			r.setDescripcio(cm.desxifrar(rCiphed.getDescripcioCiphed()));
			r.setResultat((Resultat) this
					.desxifrarEnum(cm, rCiphed.getNomResultatCiphed(), Resultat.values()));
			r.setOperacio((Operacio) this
					.desxifrarEnum(cm, rCiphed.getNomOperacioCiphed(), Operacio.values()));
			r.setUsuariDesti(this.getUsuari(cm, rCiphed.getUsuariDestiCiphed()));
			r.setUsuariOrigen(this.getUsuari(cm, rCiphed.getUsuariOrigenCiphed()));
		} else {
			CipherServiceImpl.logger.error("Resposta del servidor nula");
		}

		CipherServiceImpl.logger.debug("Resposta desxifrada: [" + r + "]");

		return r;
	}

	private Usuari desxifrarUsuari(CipherManager cm, UsuariCiphed uc) {
		Usuari u = null;
		if (uc != null) {
			if (uc instanceof MetgeCiphed) {
				u = new Metge();
			} else if (uc instanceof PacientCiphed) {
				u = new Pacient();
			} else {
				u = new Usuari();
			}
			u.setDataAlta(this.desxifrarDate(cm, uc.getDataAltaCiphed()));
			u.setDataModificacio(this.desxifrarDate(cm, uc.getDataModificacioCiphed()));
			u.setDni( cm.desxifrar(uc.getDniCiphed()) );
			u.setId( this.desxifrarInteger(cm, uc.getIdCiphed()) );
			u.setNom( cm.desxifrar(uc.getNomCiphed()) );
			u.setPrimerCognom( cm.desxifrar(uc.getPrimerCognomCiphed()) );
			u.setSegonCognom( cm.desxifrar(uc.getSegonCognomCiphed()) );
			u.setUnitatOrganitzativa(
					(UnitatOrganitzativa) this.desxifrarEnum(cm, uc.getUnitatOrganitzativaCiphed(),
							UnitatOrganitzativa.values())
			);
		}
		return u;
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.CipherService#desxifrarUsuari(com.cougil.uoc.seghismed.model.ciphed.UsuariCiphed, com.cougil.uoc.seghismed.model.Usuari)
	 */
	public Usuari desxifrarUsuari(UsuariCiphed uCiphed, Usuari destinatari) {
		Usuari u = null;
		if (uCiphed != null) {

			// desxifrem amb la clau privada de l'usuari destinatari
			P12 p12 = this.getP12(destinatari);

			CipherManager cm = new CipherManager(p12.getPrivateKey());

			u = this.getUsuari(cm, uCiphed);

		}
		return u;
	}

	private Usuari getGestor() {
		if (this.gestor == null) {
			this.gestor = SeghismedUtils.getUsuariGestor(this);
		}
		return this.gestor;
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.CipherService#getP12(com.cougil.uoc.seghismed.model.Usuari)
	 */
	public P12 getP12(Usuari usuari) {
		P12 p12 = CipherServiceImpl.p12s.get(usuari);
		// si no hem trobat el contenidor cercat, instanciem l'objecte i l'afegim al mapa
		if (p12 == null) {
			p12 = new P12(SeghismedUtils.getFileP12(usuari), SeghismedUtils.getDefPassword());
			// si l'usuari no té DNI, l'obtenim i li associem per evitar afegir usuaris
			// que no en tinguin
			if (usuari.getDni() == null) {
				Name name = (Name) p12.getCertificate().getSubjectDN();
				usuari.setDni( name.getRDN(ObjectID.dnQualifier) );
				CipherServiceImpl.p12s.put(usuari, p12);
			}
		}
		return p12;
	}

	private Usuari getUsuari(CipherManager cm, UsuariCiphed uCiphed) {
		// segons el tipus que sigui, intentem desxifrar tota la seva informació associada
		if (uCiphed instanceof MetgeCiphed) {
			return this.desxifrarMetge(cm, (MetgeCiphed) uCiphed);
		} else if (uCiphed instanceof PacientCiphed) {
			return this.desxifrarPacient(cm, (PacientCiphed) uCiphed);
		} else {
			return this.desxifrarUsuari(cm, uCiphed);
		}
	}

	/**
	 * Retorna el tipus d'usuari xifrat que pertoca, segons la classe de l'usuari
	 * desxifrat informat
	 *
	 * @param cm
	 * @param usuari
	 * @return
	 */
	private UsuariCiphed getUsuariCiphed(CipherManager cm, Usuari usuari) {
		if (usuari instanceof Metge) {
			return this.xifrarMetge(cm, (Metge) usuari);
		} else if (usuari instanceof Pacient) {
			return this.xifrarPacient(cm, (Pacient) usuari);
		} else {
			return this.xifrarUsuari(cm, usuari);
		}
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.CipherService#getX509(com.cougil.uoc.seghismed.model.Usuari)
	 */
	public X509Certificate getX509(Usuari usuari) {
		X509Certificate x509 = CipherServiceImpl.x509s.get(usuari);
		// si no hem trobat el certificat cercat, instanciem l'objecte i l'afegim al mapa
		if (x509 == null) {
			try {
				if (usuari.getCertificat() == null) {
					String fileName = SeghismedUtils.getFileCertificate(usuari);
					// SeghismedUtils.showClassAbsolutePath(this.getClass());
					URL urlResource = this.getClass().getResource(fileName);

					// truc per aconseguir obtenir els fitxers si aquests estan referenciats de forma absoluta en el fitxer de recursos
					if (urlResource == null) {
						urlResource = new URL(fileName);
					}
					CipherServiceImpl.logger.info("Loading: '"+fileName+"'");
					FileInputStream fileInput = new FileInputStream( urlResource.getFile() );
					x509 = new X509Certificate(fileInput);
				} else {
					x509 = new X509Certificate(usuari.getCertificat());
				}

				// si l'usuari no té DNI, l'obtenim i li associem per evitar afegir
				// usuaris que no en tinguin
				if (usuari.getDni() == null) {
					Name name = (Name) x509.getSubjectDN();
					usuari.setDni( name.getRDN(ObjectID.dnQualifier) );
				}
				CipherServiceImpl.x509s.put(usuari, x509);
			} catch (CertificateException e) {
				CipherServiceImpl.logger.error(e);
				throw new SeghismedException(e);
			} catch (IOException e) {
				CipherServiceImpl.logger.error(e);
				throw new SeghismedException(e);
			}
		}
		return x509;
	}

	private AlergiaCiphed signarXifrarAlergia(SignerCipherManager scm, Alergia a) {
		AlergiaCiphed ac = null;
		if (a != null) {
			ac = new AlergiaCiphed();
			ac.setDescripcioCiphed( scm.signarXifrar(a.getDescripcio()) );
			ac.setIdCiphed( this.signarXifrarInteger(scm, a.getId()) );
		}
		return ac;
	}

	private Set<AlergiaCiphed> signarXifrarAlergies(SignerCipherManager scm,
			Set<Alergia> alergies) {
		Set<AlergiaCiphed> alergiesCiphed = null;
		if (alergies != null) {
			alergiesCiphed = new HashSet<AlergiaCiphed>();
			for (Iterator<Alergia> iterator = alergies.iterator(); iterator.hasNext();) {
				Alergia alergia = iterator.next();
				alergiesCiphed.add(this.signarXifrarAlergia(scm, alergia));
			}
		}
		return alergiesCiphed;
	}


	private byte[] signarXifrarDate(SignerCipherManager scm, Date data) {
		return scm.signarXifrar(SeghismedUtils.formatDate(data));
	}

	private byte[] signarXifrarEnum(SignerCipherManager scm, SeghismedEnum enumSeghismed) {
		return scm.signarXifrar(enumSeghismed == null ? null : enumSeghismed.getNom().toString());
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.CipherService#signarXifrar(com.cougil.uoc.seghismed.model.Historial, com.cougil.uoc.seghismed.model.Usuari, com.cougil.uoc.seghismed.model.Usuari)
	 */
	public HistorialCiphed signarXifrarHistorial(Historial historial, Usuari emisor, Usuari destinatari) {
		CipherServiceImpl.logger.debug("Intentant xifrar i signar l'historial: ["+historial+"]");
		HistorialCiphed hCiphed = new HistorialCiphed();

		// xifrem amb la clau privada de l'usuari que intenta fer l'acció
		P12 p12 = this.getP12(emisor);

		// ... i amb la clau pública del destinatari
		X509Certificate x509 = this.getX509(destinatari);

		// objecte per signar i xifrar
		SignerCipherManager scm = new SignerCipherManager(p12, x509);

		// objecte per xifrar
		CipherManager cm = new CipherManager(p12.getPrivateKey(), x509);

		hCiphed.setIdCiphed( this.signarXifrarInteger(scm, historial.getId()));

		// llista de metges xifrada amb permís per accedir a l'historial i fins quan
		hCiphed.setMetgesAmbAccesProtegit(
				this.xifrarMetgesAmbAccesProtegit(cm, historial.getMetgesAmbAccesProtegit()));

		hCiphed.setPacientCiphed( this.signarXifrarPacient(scm, historial.getPacient()) );

		hCiphed.getPacientCiphed().setHistorialCiphed(hCiphed);

		//llista de descriptors de visites xifrada (metges que han visitat el pacientCiphed)
		hCiphed.setVisitesProtegides(
				this.signarXifrarVisitesCiphedProtegides(scm, cm, historial
				.getVisitesProtegides()));

		CipherServiceImpl.logger.debug("Historial xifrat i signat: ["+hCiphed+"]");
		return hCiphed;
	}

	private byte[] signarXifrarInteger(SignerCipherManager scm, Integer integer) {
		return scm.signarXifrar(SeghismedUtils.formatInteger(integer));
	}


	/**
	 * Retorna una llista amb el conjunt de pacients amb accés protegit després d'analitzar la
	 * llista informada i xifrada només per al Gestor del sistema
	 */
	private List<PacientCiphed> signarXifrarLlistaPacientsProtegits(
			SignerCipherManager scm, List<PacientCiphed> pacientsCiphedGestor) {

		// la col·lecció està xifrada i signada només per al gestor, per tal la desxifrem
		List<Pacient> pacientsDeciphed = this.verificarDesxifrarLListaPacientsProtegits(
				pacientsCiphedGestor, this.getGestor());

		// i per últim xifrem i signem la llista de metges desxifrada per al seu destinatari
		return this.signarXifrarLlistaPacientsProtegitsDeciphed(scm, pacientsDeciphed);
	}

	/**
	 * Retorna un llista de pacients protegits xifrat i signat per un destinatari després
	 * d'analitzar el mapa de pacients desxifrat
	 */
	private List<PacientCiphed> signarXifrarLlistaPacientsProtegitsDeciphed(
			SignerCipherManager scm, List<Pacient> pacientsDeciphed) {
		List<PacientCiphed> pacients = new ArrayList<PacientCiphed>();

		for (Iterator<Pacient> iterator = pacientsDeciphed.iterator(); iterator.hasNext();) {
			Pacient p = iterator.next();

			// xifrem el pacient
			PacientCiphed pc = this.signarXifrarPacient(scm, p);

			pacients.add(pc);
		}
		return pacients;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * com.cougil.uoc.seghismed.business.CipherService#signarXifrarMetge(com.cougil.uoc.seghismed
	 * .model.Metge, com.cougil.uoc.seghismed.model.Usuari, com.cougil.uoc.seghismed.model.Usuari)
	 */
	// public MetgeCiphed signarXifrarMetge(Metge metge, Usuari emisor, Usuari destinatari) {
	// MetgeCiphed mc = null;
	// if (metge != null) {
	//
	// // xifrem amb la clau privada de l'usuari que intenta fer l'acció
	// P12 p12 = this.getP12(emisor);
	//
	// // ... i amb la clau pública del destinatari
	// X509Certificate x509 = this.getX509(destinatari);
	//
	// SignerCipherManager scm = new SignerCipherManager(p12, x509);
	//
	// mc = this.signarXifrarMetge(scm, metge);
	// }
	// return mc;
	// }

	// private MetgeCiphed signarXifrarMetge(SignerCipherManager scm, Metge m) {
	// MetgeCiphed mc = (MetgeCiphed) this.signarXifrarUsuari(scm, m);
	// if (mc != null) {
	// mc.setEspecialitatCiphed(scm.signarXifrar(m.getEspecialitat()));
	// mc.setNumeroColegiatCiphed(scm.signarXifrar(m.getNumeroColegiat()));
	// mc.setLlistaPacientsProt(this.signarXifrarLlistaPacientsProtegits(scm,
	// m.getLlistaPacientsProt()));
	// }
	// return mc;
	// }


	/**
	 * Retorna un mapa amb la llista de metges amb accés protegit després d'analitzar el
	 * mapa informat i xifrat només per al Gestor del sistema
	 */
	// private Map<MetgeCiphed, Date> signarXifrarMetgesCiphedAmbAccesProtegit(
	// SignerCipherManager scm, Map<MetgeCiphed, Date> metgesCiphedGestor) {
	//
	// // la llista està xifrada i signada només per al gestor, per tal la desxifrem
	// Map<Metge, Date> metgesDeciphed = this.verificarDesxifrarMetgesAmbAccesProtegit(
	// metgesCiphedGestor, this.getGestor());
	//
	// // i per últim xifrem i signem la llista de metges desxifrada per al seu destinatari
	// return this.signarXifrarMetgesDeciphedAmbAccesProtegit(scm, metgesDeciphed);
	// }

	/**
	 * Retorna un mapa amb la llista de metges amb accés protegit xifrat i signat per un
	 * destinatari després d'analitzar el mapa de metges desxifrat
	 */
	// private Map<MetgeCiphed, Date> signarXifrarMetgesDeciphedAmbAccesProtegit(SignerCipherManager
	// scm,
	// Map<Metge, Date> metges) {
	// Map<MetgeCiphed, Date> metgesCiphed = new HashMap<MetgeCiphed, Date>();
	//
	// for (Iterator<Metge> iterator = metges.keySet().iterator(); iterator.hasNext();) {
	// Metge m = iterator.next();
	//
	// // xifrem i signem el metge amb la clau del destinatari
	// MetgeCiphed mc = this.signarXifrarMetge(scm, m);
	//
	// // associem també la data
	// Date d = metges.get(m);
	//
	// metgesCiphed.put(mc, d);
	// }
	//
	// return metgesCiphed;
	// }

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * com.cougil.uoc.seghismed.business.CipherService#signarXifrarPacient(com.cougil.uoc.seghismed
	 * .model.Pacient, com.cougil.uoc.seghismed.model.Usuari, com.cougil.uoc.seghismed.model.Usuari)
	 */
	public PacientCiphed signarXifrarPacient(Pacient pacient, Usuari emisor, Usuari destinatari) {
		PacientCiphed pc = null;
		if (pacient != null) {

			// xifrem amb la clau privada de l'usuari que intenta fer l'acció
			P12 p12 = this.getP12(emisor);

			// ... i amb la clau pública del destinatari
			X509Certificate x509 = this.getX509(destinatari);

			SignerCipherManager scm = new SignerCipherManager(p12, x509);

			pc = this.signarXifrarPacient(scm, pacient);
			// per defecte no incloem la informació de l'historial (per seguretat i per
			// evitar crides recursives)
			// pc.setHistorialCiphed(historialCiphed);
		}
		return pc;
	}



	private PacientCiphed signarXifrarPacient(SignerCipherManager scm, Pacient p) {
		PacientCiphed pc = (PacientCiphed) this.signarXifrarUsuari(scm, p);
		pc.setAlergiesCiphed(this.signarXifrarAlergies(scm, p.getAlergies()));
		pc.setGrupSanguiniCiphed(this.signarXifrarEnum(scm, p.getGrupSanguini()));
		return pc;
	}

	private UsuariCiphed signarXifrarUsuari(SignerCipherManager scm, Usuari u) {
		UsuariCiphed uc = null;
		if (u != null) {
			if (u instanceof Metge) {
				uc = new MetgeCiphed();
			} else if (u instanceof Pacient) {
				uc = new PacientCiphed();
			} else {
				uc = new UsuariCiphed();
			}
			uc.setDataAltaCiphed(this.signarXifrarDate(scm, u.getDataAlta()));
			uc.setDataModificacioCiphed(this.signarXifrarDate(scm, u.getDataModificacio()));
			uc.setDniCiphed( scm.signarXifrar(u.getDni()) );
			uc.setIdCiphed( this.signarXifrarInteger(scm, u.getId()) );
			uc.setNomCiphed( scm.signarXifrar(u.getNom()) );
			uc.setPrimerCognomCiphed( scm.signarXifrar(u.getPrimerCognom()) );
			uc.setSegonCognomCiphed( scm.signarXifrar(u.getSegonCognom()) );
			uc.setUnitatOrganitzativaCiphed( this.signarXifrarEnum(scm, u.getUnitatOrganitzativa()) );
		}
		return uc;
	}

	private VisitaCiphed signarXifrarVisita(SignerCipherManager scm, CipherManager cm, Visita v) {
		VisitaCiphed vc = null;
		if (v != null) {
			vc = new VisitaCiphed();
			vc.setAnamnesiCiphed(scm.signarXifrar(v.getAnamnesi()));
			vc.setDataAltaCiphed(this.signarXifrarDate(scm, v.getDataAlta()));
			vc.setDataHoraCiphed(this.signarXifrarDate(scm, v.getDataHora()));
			vc.setDataModificacioCiphed(this.signarXifrarDate(scm, v.getDataModificacio()));
			vc.setDiagnosiCiphed(scm.signarXifrar(v.getDiagnosi()));
			vc.setIdCiphed(this.signarXifrarInteger(scm, v.getId()));
			vc.setTemaCiphed(scm.signarXifrar(v.getTema()));
			vc.setTractamentCiphed(scm.signarXifrar(v.getTractament()));
			// per últim, xifrem el metge
			vc.setMetgeCiphed(this.xifrarMetge(cm, v.getMetge()));
		}
		return vc;
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.CipherService#signarXifrarVisita(com.cougil.uoc.seghismed.model.Visita, com.cougil.uoc.seghismed.model.Usuari, com.cougil.uoc.seghismed.model.Usuari)
	 */
	public VisitaCiphed signarXifrarVisita(Visita visita, Usuari emisor, Usuari destinatari) {
		VisitaCiphed pc = null;
		if (visita != null) {

			// xifrem amb la clau privada de l'usuari que intenta fer l'acció
			P12 p12 = this.getP12(emisor);

			// ... i amb la clau pública del destinatari
			X509Certificate x509 = this.getX509(destinatari);

			// instanciem l'objecte per signar la informació
			SignerCipherManager scm = new SignerCipherManager(p12, x509);

			// per poder xifrar el metge associat, emprarem també la clau privada de l'usuari que
			// intenta fer l'acció i la clau pública del destinatari
			CipherManager cm = new CipherManager(p12.getPrivateKey(), x509);

			pc = this.signarXifrarVisita(scm, cm, visita);
		}
		return pc;
	}

	/**
	 * Retorna un mapa amb la llista de visites protegides amb accés protegit després
	 * d'analitzar el mapa informat i xifrat només per al Gestor del sistema
	 */
	private Set<VisitaCiphed> signarXifrarVisitesCiphedProtegides(
			SignerCipherManager scm, CipherManager cm,
			Set<VisitaCiphed> visitesCiphedGestor) {

		// la llista està xifrada i signada només per al gestor, per tal la desxifrem
		Set<Visita> visitesDeciphed = this.verificarDesxifrarVisitesProtegides(visitesCiphedGestor,
				this.getGestor());

		// xifrem i signem la llista de visites desxifrada per al seu destinatari
		return this.signarXifrarVisitesDeciphedProtegides(scm, cm, visitesDeciphed);
	}

	/**
	 * Retorna un mapa amb la llista de visites protegides xifrada i signada per un
	 * destinatari després d'analitzar el mapa de visites desxifrada
	 */
	private Set<VisitaCiphed> signarXifrarVisitesDeciphedProtegides(SignerCipherManager scm,
			CipherManager cm, Set<Visita> visites) {
		Set<VisitaCiphed> visitesCiphed = null;
		if (visites != null) {
			visitesCiphed = new HashSet<VisitaCiphed>();
			for (Iterator<Visita> iterator = visites.iterator(); iterator.hasNext();) {
				Visita v = iterator.next();

				// xifrem i signem la visita amb la clau del destinatari
				visitesCiphed.add(this.signarXifrarVisita(scm, cm, v));
			}
		}
		return visitesCiphed;
	}

	private Alergia verificarDesxifrarAlergia(SignerCipherManager scm, AlergiaCiphed ac) {
		Alergia a = null;
		if (ac != null) {
			a = new Alergia();
			a.setDescripcio( scm.verificarDesxifrar(ac.getDescripcioCiphed()) );
			a.setId( this.verificarDesxifrarInteger(scm, ac.getIdCiphed()) );
		}
		return a;
	}

	private Set<Alergia> verificarDesxifrarAlergies(SignerCipherManager scm,
			Set<AlergiaCiphed> alergiesCiphed) {
		Set<Alergia> alergies = null;
		if (alergiesCiphed != null) {
			alergies = new HashSet<Alergia>();
			for (Iterator<AlergiaCiphed> iterator = alergiesCiphed.iterator(); iterator.hasNext();) {
				AlergiaCiphed alergiaCiphed = iterator.next();
				alergies.add(this.verificarDesxifrarAlergia(scm, alergiaCiphed));
			}
		}
		return alergies;
	}

	private Date verificarDesxifrarDate(SignerCipherManager scm, byte[] data) {
		return SeghismedUtils.parseDate(scm.verificarDesxifrar(data));
	}

	private Enum verificarDesxifrarEnum(SignerCipherManager scm, byte[] enumerat, Enum[] values) {
		return SeghismedUtils.parseEnum( scm.verificarDesxifrar(enumerat), values );
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.CipherService#verificarDesxifrar(com.cougil.uoc.seghismed.model.Historial, com.cougil.uoc.seghismed.model.Usuari)
	 */
	public Historial verificarDesxifrarHistorial(HistorialCiphed hCiphed, Usuari destinatari) {
		CipherServiceImpl.logger.debug("Intentant desxifrar i verificar l'historial: ["+hCiphed+"]");
		Historial h = new Historial();

		// desxifrem amb la clau privada de l'usuari que intenta fer l'acció
		P12 p12 = this.getP12(destinatari);

		SignerCipherManager scm = new SignerCipherManager(p12.getPrivateKey());

		h.setId( this.verificarDesxifrarInteger(scm, hCiphed.getIdCiphed()));

		// la llista de metges amb permís per accedir a l'historial i fins quan
		// Ja està xifrada només per al destinatari !!
		//Map<Metge, Date> metges = verificarDesxifrarMetgesAmbAccesProtegit( scm, hCiphed.getMetgesAmbAccesProtegit());

		h.setMetgesAmbAccesProtegit( hCiphed.getMetgesAmbAccesProtegit() );

		h.setPacient( this.verificarDesxifrarPacient(scm, hCiphed.getPacientCiphed()) );

		//llista de descriptors de visites xifrada (metges que han visitat el pacientCiphed)
		// Ja està xifrada només per al destinatari !!
		h.setVisitesProtegides( hCiphed.getVisitesProtegides() );

		CipherServiceImpl.logger.debug("Historial desxifrat i verificat: [" + h + "]");
		return h;
	}

	private Integer verificarDesxifrarInteger(SignerCipherManager scm, byte[] integer) {
		return SeghismedUtils.parseInteger( scm.verificarDesxifrar(integer) );
	}

	private List<Pacient> verificarDesxifrarLListaPacientsProtegits(List<PacientCiphed> pacientsCiphed,
			Usuari destinatari) {
		P12 p12 = this.getP12(destinatari);
		SignerCipherManager scmDecrypt = new SignerCipherManager(p12.getPrivateKey());
		return this.verificarDesxifrarLListaPacientsProtegits(scmDecrypt, pacientsCiphed);
	}

	private List<Pacient> verificarDesxifrarLListaPacientsProtegits(SignerCipherManager scm,
			List<PacientCiphed> pacientsCiphed) {
		List<Pacient> pacients = new ArrayList<Pacient>();

		for (Iterator<PacientCiphed> iterator = pacientsCiphed.iterator(); iterator.hasNext();) {
			PacientCiphed pacientCiphedGestor = iterator.next();

			// desxifrem el pacient
			Pacient p = this.verificarDesxifrarPacient(scm, pacientCiphedGestor);

			pacients.add(p);
		}

		return pacients;
	}

	public Metge verificarDesxifrarMetge(MetgeCiphed mCiphed, Usuari destinatari) {
		Metge m = null;
		if (mCiphed != null) {

			// desxifrem amb la clau privada de l'usuari que intenta fer l'acció
			P12 p12 = this.getP12(destinatari);

			SignerCipherManager scm = new SignerCipherManager(p12.getPrivateKey());

			m = this.verificarDesxifrarMetge(scm, mCiphed);

		}
		return m;
	}

	private Metge verificarDesxifrarMetge(SignerCipherManager scm, MetgeCiphed mc) {
		Metge m = (Metge) this.verificarDesxifrarUsuari(scm, mc);
		if (m != null) {
			m.setEspecialitat(scm.verificarDesxifrar(mc.getEspecialitatCiphed()));
			m.setNumeroColegiat(scm.verificarDesxifrar(mc.getNumeroColegiatCiphed()));
			m.setLlistaPacientsProt(this.signarXifrarLlistaPacientsProtegits(scm, mc.getLlistaPacientsProt()));
		}
		return m;
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.CipherService#verificarDesxifrarMetgesAmbAccesProtegit(java.util.Map, com.cougil.uoc.seghismed.model.Usuari)
	 */
	public Map<Metge, Date> verificarDesxifrarMetgesAmbAccesProtegit(
			Map<MetgeCiphed, Date> metgesCiphed, Usuari destinatari) {
		P12 p12 = this.getP12(destinatari);
		SignerCipherManager scmDecrypt = new SignerCipherManager(p12.getPrivateKey());
		return this.verificarDesxifrarMetgesAmbAccesProtegit(scmDecrypt, metgesCiphed);
	}

	private Map<Metge, Date> verificarDesxifrarMetgesAmbAccesProtegit(SignerCipherManager scm,
			Map<MetgeCiphed, Date> metgesCiphed) {
		Map<Metge, Date> metges = new HashMap<Metge, Date>();

		for (Iterator<MetgeCiphed> iterator = metgesCiphed.keySet().iterator(); iterator.hasNext();) {
			MetgeCiphed metgeCiphedGestor = iterator.next();

			// desxifrem el metge
			Metge m = this.verificarDesxifrarMetge(scm, metgeCiphedGestor);

			// agafem també la data
			Date d = metgesCiphed.get(metgeCiphedGestor);

			metges.put(m, d);
		}
		return metges;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * com.cougil.uoc.seghismed.business.CipherService#verificarDesxifrarPacient(com.cougil.uoc.
	 * seghismed.model.ciphed.PacientCiphed, com.cougil.uoc.seghismed.model.Usuari)
	 */
	public Pacient verificarDesxifrarPacient(PacientCiphed pCiphed, Usuari destinatari) {
		Pacient p = null;
		if (pCiphed != null) {

			// desxifrem amb la clau privada de l'usuari que intenta fer l'acció
			P12 p12 = this.getP12(destinatari);

			SignerCipherManager scm = new SignerCipherManager(p12.getPrivateKey());

			p = this.verificarDesxifrarPacient(scm, pCiphed);

		}
		return p;
	}

	private Pacient verificarDesxifrarPacient(SignerCipherManager scm, PacientCiphed pc) {
		Pacient p = (Pacient) this.verificarDesxifrarUsuari(scm, pc);
		if (p != null) {
			p.setGrupSanguini((GrupSanguini) this.verificarDesxifrarEnum(scm, pc.getGrupSanguiniCiphed(),
					GrupSanguini.values()));
			p.setAlergies(this.verificarDesxifrarAlergies(scm, pc.getAlergiesCiphed()));
		}
		return p;
	}


	private Usuari verificarDesxifrarUsuari(SignerCipherManager scm, UsuariCiphed uc) {
		Usuari u = null;
		if (uc != null) {
			if (uc instanceof MetgeCiphed) {
				u = new Metge();
			} else if (uc instanceof PacientCiphed) {
				u = new Pacient();
			} else {
				u = new Usuari();
			}
			u.setDataAlta(this.verificarDesxifrarDate(scm, uc.getDataAltaCiphed()));
			u.setDataModificacio(this.verificarDesxifrarDate(scm, uc.getDataModificacioCiphed()));
			u.setDni( scm.verificarDesxifrar(uc.getDniCiphed()) );
			u.setId( this.verificarDesxifrarInteger(scm, uc.getIdCiphed()) );
			u.setNom( scm.verificarDesxifrar(uc.getNomCiphed()) );
			u.setPrimerCognom( scm.verificarDesxifrar(uc.getPrimerCognomCiphed()) );
			u.setSegonCognom( scm.verificarDesxifrar(uc.getSegonCognomCiphed()) );
			u.setUnitatOrganitzativa(
					(UnitatOrganitzativa) this.verificarDesxifrarEnum(scm, uc.getUnitatOrganitzativaCiphed(),
							UnitatOrganitzativa.values())
			);
		}
		return u;
	}

	private Visita verificarDesxifrarVisita(SignerCipherManager scm, CipherManager cm, VisitaCiphed vc) {
		Visita v = null;
		if (vc != null) {
			v = new Visita();
			v.setAnamnesi(scm.verificarDesxifrar(vc.getAnamnesiCiphed()));
			v.setDataAlta( this.verificarDesxifrarDate(scm, vc.getDataAltaCiphed()) );
			v.setDataHora( this.verificarDesxifrarDate(scm, vc.getDataHoraCiphed()) );
			v.setDataModificacio( this.verificarDesxifrarDate(scm, vc.getDataModificacioCiphed()) );
			v.setDiagnosi( scm.verificarDesxifrar( vc.getDiagnosiCiphed()) );
			v.setId( this.verificarDesxifrarInteger(scm, vc.getIdCiphed()) );
			v.setTema( scm.verificarDesxifrar( vc.getTemaCiphed()) );
			v.setTractament(scm.verificarDesxifrar(vc.getTractamentCiphed()));
			// per últim desxifrem el metge
			v.setMetge(this.desxifrarMetge(cm, vc.getMetgeCiphed()));
		}
		return v;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * com.cougil.uoc.seghismed.business.CipherService#verificarDesxifrarVisita(com.cougil.uoc.seghismed
	 * .model.ciphed.VisitaCiphed, com.cougil.uoc.seghismed.model.Usuari)
	 */
	public Visita verificarDesxifrarVisita(VisitaCiphed vCiphed, Usuari destinatari) {
		Visita v = null;
		if (vCiphed != null) {

			// desxifrem amb la clau privada de l'usuari que intenta fer l'acció
			P12 p12 = this.getP12(destinatari);

			// objecte per verificar i desxifrar la informació
			SignerCipherManager scm = new SignerCipherManager(p12.getPrivateKey());

			// objecte per desxifrar
			CipherManager cm = new CipherManager(p12.getPrivateKey());

			v = this.verificarDesxifrarVisita(scm, cm, vCiphed);
		}
		return v;
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.CipherService#verificarDesxifrarVisitesProtegides(java.util.Set, com.cougil.uoc.seghismed.model.Usuari)
	 */
	public Set<Visita> verificarDesxifrarVisitesProtegides(Set<VisitaCiphed> visitesProtegides,
			Usuari destinatari) {
		P12 p12 = this.getP12(destinatari);
		SignerCipherManager scmDecrypt = new SignerCipherManager(p12.getPrivateKey());
		CipherManager cmDecrypt = new CipherManager(p12.getPrivateKey());
		return this.verificarDesxifrarVisitesProtegides(scmDecrypt, cmDecrypt, visitesProtegides);
	}

	private Set<Visita> verificarDesxifrarVisitesProtegides(SignerCipherManager scm,
			CipherManager cmDecrypt,
			Set<VisitaCiphed> visitesCiphed) {
		Set<Visita> visites = null;
		if (visitesCiphed != null) {
			visites = new HashSet<Visita>();
			for (Iterator<VisitaCiphed> iterator = visitesCiphed.iterator(); iterator.hasNext();) {
				VisitaCiphed visitaCiphed = iterator.next();

				// desxifrem la visita
				Visita v = this.verificarDesxifrarVisita(scm, cmDecrypt, visitaCiphed);

				visites.add(v);
			}
		}
		return visites;
	}

	private AlergiaCiphed xifrarAlergia(CipherManager cm, Alergia a) {
		AlergiaCiphed ac = null;
		if (a != null) {
			ac = new AlergiaCiphed();
			ac.setDescripcioCiphed( cm.xifrar(a.getDescripcio()) );
			ac.setIdCiphed( this.xifrarInteger(cm, a.getId()) );
		}
		return ac;
	}

	private Set<AlergiaCiphed> xifrarAlergies(CipherManager cm, Set<Alergia> alergies) {
		Set<AlergiaCiphed> alergiesCiphed = null;
		// el conjunt d'al·lergies pot estar buida
		if (alergies != null) {
			alergiesCiphed = new HashSet<AlergiaCiphed>();
			for (Iterator<Alergia> iterator = alergies.iterator(); iterator.hasNext();) {
				Alergia alergia = iterator.next();
				alergiesCiphed.add( this.xifrarAlergia(cm, alergia) );
			}
		}
		return alergiesCiphed;
	}

	private byte[] xifrarDate(CipherManager cm, Date data) {
		return cm.xifrar(SeghismedUtils.formatDate(data));
	}

	private byte[] xifrarEnum(CipherManager cm, SeghismedEnum enumSeghismed) {
		return cm.xifrar(enumSeghismed == null ? null : enumSeghismed.getNom().toString());
	}

	private byte[] xifrarInteger(CipherManager cm, Integer integer) {
		return cm.xifrar(SeghismedUtils.formatInteger(integer));
	}

	private MetgeCiphed xifrarMetge(CipherManager cm, Metge metge) {
		MetgeCiphed mc = (MetgeCiphed) this.xifrarUsuari(cm, metge);
		if (mc != null) {
			mc.setNumeroColegiatCiphed(cm.xifrar(metge.getNumeroColegiat()));
			mc.setEspecialitatCiphed(cm.xifrar(metge.getEspecialitat()));
			// per defecte no incloem la informació del seus pacients protegits
			// mc.setLlistaPacientsProt(this.xifrarPacientsProtegits(cm, metge.getLlistaPacientsProt()));
		}
		return mc;
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.CipherService#xifrarMetge(com.cougil.uoc.seghismed.model.Metge, com.cougil.uoc.seghismed.model.Usuari, com.cougil.uoc.seghismed.model.Usuari)
	 */
	@Override
	public MetgeCiphed xifrarMetge(Metge metge, Usuari emisor, Usuari destinatari) {
		MetgeCiphed mc = null;
		if (metge != null) {

			// xifrem amb la clau privada de l'usuari que intenta fer l'acció
			P12 p12 = this.getP12(emisor);

			// ... i amb la clau pública del destinatari
			X509Certificate x509 = this.getX509(destinatari);

			CipherManager cm = new CipherManager(p12.getPrivateKey(), x509);

			mc = this.xifrarMetge(cm, metge);
		}
		return mc;
	}

	/**
	 * Retorna un mapa amb la llista de metges amb accés protegit després d'analitzar el
	 * mapa informat i xifrat només per al Gestor del sistema
	 */
	private Map<MetgeCiphed, Date> xifrarMetgesAmbAccesProtegit(CipherManager cm,
			Map<MetgeCiphed, Date> metgesAmbAccesProtegit) {

		// la llista està xifrada només per al gestor, per tal la desxifrem
		Map<Metge, Date> metgesDeciphed = this.desxifrarMetgesAmbAccesProtegit(
				metgesAmbAccesProtegit, this.getGestor());

		// i per últim xifrem la llista de metges desxifrada per al seu destinatari
		return this.xifrarMetgesDeciphedAmbAccesProtegit(cm, metgesDeciphed);
	}

	/**
	 * Retorna un mapa amb la llista de metges amb accés protegit xifrat per un
	 * destinatari després d'analitzar el mapa de metges desxifrat
	 */
	private Map<MetgeCiphed, Date> xifrarMetgesDeciphedAmbAccesProtegit(CipherManager cm,
			Map<Metge, Date> metges) {

		Map<MetgeCiphed, Date> metgesCiphed = new HashMap<MetgeCiphed, Date>();

		for (Iterator<Metge> iterator = metges.keySet().iterator(); iterator.hasNext();) {
			Metge m = iterator.next();

			// xifrem i signem el metge amb la clau del destinatari
			MetgeCiphed mc = this.xifrarMetge(cm, m);

			// associem també la data
			Date d = metges.get(m);

			metgesCiphed.put(mc, d);
		}

		return metgesCiphed;
	}

	private PacientCiphed xifrarPacient(CipherManager cm, Pacient emisor) {
		PacientCiphed pc = (PacientCiphed) this.xifrarUsuari(cm, emisor);
		pc.setAlergiesCiphed( this.xifrarAlergies(cm, emisor.getAlergies()) );
		pc.setGrupSanguiniCiphed( this.xifrarEnum(cm, emisor.getGrupSanguini()));
		// per defecte no incloem la informació de l'historial (per seguretat i per evitar crides recursives)
		return pc;
	}

	public PacientCiphed xifrarPacient(Pacient pacient, Usuari emisor, Usuari destinatari) {
		PacientCiphed pc = null;
		if (pacient != null) {

			// xifrem amb la clau privada de l'usuari que intenta fer l'acció
			P12 p12 = this.getP12(emisor);

			// ... i amb la clau pública del destinatari
			X509Certificate x509 = this.getX509(destinatari);

			CipherManager cm = new CipherManager(p12.getPrivateKey(), x509);

			pc = this.xifrarPacient(cm, pacient);
		}
		return pc;
	}

	/**
	 * Retorna una llista amb el conjunt de pacients protegits després d'analitzar la llista
	 * informada i xifrada només per al Gestor del sistema
	 */
	private List<PacientCiphed> xifrarPacientsProtegits(CipherManager cm,
			List<PacientCiphed> pacientsProtGestor) {

		// la llista està xifrada i signada només per al gestor, per tal la desxifrem
		List<Pacient> pacientsDeciphed = this.desxifrarPacientsProtegits(pacientsProtGestor,
				this.getGestor());

		// i per últim xifrem la llista de pacients desxifrada per al seu destinatari
		return this.xifrarPacientsProtegitsDeciphed(cm, pacientsDeciphed);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see com.cougil.uoc.seghismed.business.CipherService#xifrarPacientsProtegits(java.util.List,
	 * com.cougil.uoc.seghismed.model.Metge)
	 */
	public List<PacientCiphed> xifrarPacientsProtegits(List<PacientCiphed> pacientsProtGestor, Usuari emisor,
			Usuari destinatari) {

		// xifrem amb la clau privada de l'usuari que intenta fer l'acció
		P12 p12 = this.getP12(emisor);

		// ... i amb la clau pública del destinatari
		X509Certificate x509 = this.getX509(destinatari);

		CipherManager cm = new CipherManager(p12.getPrivateKey(), x509);

		return this.xifrarPacientsProtegits(cm, pacientsProtGestor);
	}

	/**
	 * Retorna un llista de pacients protegits xifrats per un destinatari després d'analitzar el
	 * mapa de pacients desxifrat
	 */
	private List<PacientCiphed> xifrarPacientsProtegitsDeciphed(CipherManager cm,
			List<Pacient> pacientsDeciphed) {
		List<PacientCiphed> pacients = null;
		if (pacientsDeciphed != null) {
			pacients = new ArrayList<PacientCiphed>();
			for (Iterator<Pacient> iterator = pacientsDeciphed.iterator(); iterator.hasNext();) {
				Pacient p = iterator.next();

				// xifrem el pacient
				PacientCiphed pc = this.xifrarPacient(cm, p);

				pacients.add(pc);
			}
		}
		return pacients;
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.CipherService#xifrar(com.cougil.uoc.seghismed.model.comunicacions.Peticio, com.cougil.uoc.seghismed.model.Usuari, com.cougil.uoc.seghismed.model.Usuari)
	 */
	public PeticioCiphed xifrarPeticio(Peticio p, Usuari emisor, Usuari destinatari) {
		CipherServiceImpl.logger.debug("Intentant xifrar la peticio: ["+p+"]");
		PeticioCiphed pCiphed = new PeticioCiphed();

		// xifrem amb la clau privada de l'usuari que intenta fer l'acció
		P12 p12 = this.getP12(emisor);

		// ... i amb la clau pública del destinatari
		X509Certificate x509 = this.getX509(destinatari);

		CipherManager cm = new CipherManager(p12.getPrivateKey(),x509);

		pCiphed.setNgCiphed( this.xifrarInteger(cm, p.getNg()) );
		pCiphed.setNiCiphed( this.xifrarInteger(cm, p.getNi()) );
		pCiphed.setNomOperacioCiphed( this.xifrarEnum(cm, p.getOperacio()));
		pCiphed.setUsuariDestiCiphed(this.getUsuariCiphed(cm, p.getUsuariDesti()));
		pCiphed.setUsuariOrigenCiphed(this.getUsuariCiphed(cm, p.getUsuariOrigen()));

		CipherServiceImpl.logger.debug("Peticio xifrada: ["+pCiphed+"]");
		return pCiphed;
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.CipherService#xifrar(com.cougil.uoc.seghismed.model.comunicacions.Resposta, com.cougil.uoc.seghismed.model.Usuari, com.cougil.uoc.seghismed.model.Usuari)
	 */
	@Override
	public RespostaCiphed xifrarResposta(Resposta r, Usuari emisor, Usuari destinatari) {
		CipherServiceImpl.logger.debug("Intentant xifrar la resposta: ["+r+"]");
		RespostaCiphed rCiphed = null;

		if (emisor != null && destinatari != null) {
			rCiphed = new RespostaCiphed();

			// xifrem amb la clau privada de l'usuari que intenta fer l'acció
			P12 p12 = this.getP12(emisor);

			// ... i amb la clau pública del destinatari
			X509Certificate x509 = this.getX509(destinatari);

			CipherManager cm = new CipherManager(p12.getPrivateKey(), x509);

			rCiphed.setNgCiphed(this.xifrarInteger(cm, r.getNg()));
			rCiphed.setNiCiphed(this.xifrarInteger(cm, r.getNi()));
			rCiphed.setDescripcioCiphed(cm.xifrar(r.getDescripcio()));
			rCiphed.setNomResultatCiphed(this.xifrarEnum(cm, r.getResultat()));
			rCiphed.setNomOperacioCiphed(this.xifrarEnum(cm, r.getOperacio()));
			rCiphed.setUsuariDestiCiphed(this.getUsuariCiphed(cm, r.getUsuariDesti()));
			rCiphed.setUsuariOrigenCiphed(this.getUsuariCiphed(cm, r.getUsuariOrigen()));

		} else {
			CipherServiceImpl.logger.error("Algun usuari no és vàlid. Emisor: [" + emisor
					+ "] Destinatari: [" + destinatari + "]");
		}

		CipherServiceImpl.logger.debug("Resposta xifrada: ["+rCiphed+"]");

		return rCiphed;
	}

	private UsuariCiphed xifrarUsuari(CipherManager cm, Usuari u) {
		UsuariCiphed uc = null;
		if (u != null) {
			if (u instanceof Metge) {
				uc = new MetgeCiphed();
			} else if (u instanceof Pacient) {
				uc = new PacientCiphed();
			} else {
				uc = new UsuariCiphed();
			}
			uc.setDataAltaCiphed(this.xifrarDate(cm, u.getDataAlta()));
			uc.setDataModificacioCiphed(this.xifrarDate(cm, u.getDataModificacio()));
			uc.setDniCiphed(cm.xifrar(u.getDni()));
			uc.setIdCiphed(this.xifrarInteger(cm, u.getId()));
			uc.setNomCiphed(cm.xifrar(u.getNom()));
			uc.setPrimerCognomCiphed(cm.xifrar(u.getPrimerCognom()));
			uc.setSegonCognomCiphed(cm.xifrar(u.getSegonCognom()));
			uc.setUnitatOrganitzativaCiphed(this.xifrarEnum(cm, u.getUnitatOrganitzativa()));
		}
		return uc;
	}

}
